/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.server.main;

import com.core.log.Debug;
import com.core.utils.DateUtil;
import com.server.connection.ConnectionHandler;
import com.server.connection.IConnectionListenner;
import com.server.database.*;
import com.server.game.*;
import com.server.pool.PoolElement;
import java.io.IOException;
import java.net.Socket;
import java.sql.Timestamp;
import java.util.List;
import java.util.Vector;
import process.ICardCharger;

/**
 *
 * @author daz
 */
public class ClientManager implements IConnectionListenner, PoolElement {

    public static final int BUY_ITEM = 0;
    public static final int APP_ITEM = 1;
    private static final int THREAD_SLEEP = 50;
    private static final int DELAY_PING = 15000;
    private static final int DELAY_OUT = 180000;
    private static final int AVATAR_CONST = 4;
    public int clientVersionCode = 1;
    private long clientId;
    private long startTime;
    private long startTimeDb;
    private long timeExpireDb;
    private long transRef;
    private int companyId;
    private boolean isRunning;
    private boolean isEnterTable;
    private boolean isKickOut;
    private ConnectionHandler connectionHandler;
    private ServerManager serverManager;
    private GameManager gameManager;
    private DataEngine dataEngine = DataEngine.getInstance();
    private String clientName;
    private UserInfo userInfo;
    private GamePlayer player;
    private GameTable gameTable;
    private Vector<String> inQueue;
    private int gameType, roomId, tableId, playerId;
    private int countPing;
    private Socket clientSocket;
    private Shop shop;
    private List<Item> inventory;
    private MateInfo mateInfo;
    private List<UserMessage> listMessage;
    private List<String> listSmsInfo;
    private List<ListItem> listItemInfo;
    private ItemInfo itemInfo;
    private XengGame xengGame;
    public String device = "J2ME";
    private Thread clientThread;

    public ClientManager(ServerManager server, Socket clientSocket, long clientId) throws IOException {
        this.connectionHandler = new ConnectionHandler(clientSocket, this);
        this.serverManager = server;
        this.clientId = clientId;
        this.clientSocket = clientSocket;
        gameManager = serverManager.getGameManager();
        clientName = "";
        isEnterTable = false;
        inQueue = new Vector<String>();
        roomId = -1;
        xengGame = new XengGame(this);
        shop = new Shop(this, gameManager);
        isRunning = true;
    }

    public void setPlayerId(int playerId) {
        this.playerId = playerId;
    }

    public void setTableId(int tableId) {
        this.tableId = tableId;
    }

    public void setRoomId(int roomId) {
        this.roomId = roomId;
    }

    public int getTableId() {
        return tableId;
    }

    public void setGameType(int gameType) {
        this.gameType = gameType;
    }

    public int getRoomId() {
        return roomId;
    }

    public int getGameType() {
        return gameType;
    }

    @Override
    public void stop() {
        if (connectionHandler != null) {
            connectionHandler.stopConnection();
        }
        connectionHandler = null;
        isRunning = false;
    }

    @Override
    public void dispose() {
        isRunning = false;
        if (clientName != null) {
            if (clientName.length() > 0 && !isKickOut) {
                dataEngine.exitServer(clientName);
            }
        }
        // thoat khoi ban
        if (gameTable != null) {
            if (isEnterTable) {
                gameTable.removeUser(playerId);
            }
        }
        //thoat khoi phong
        if (roomId >= 0 && gameManager != null) {
            gameManager.exitRoom(this);
        }
        if (gameManager != null) {
            gameManager.removeFromMap(clientName);
        }
        if (serverManager != null) {
            serverManager.removeClient(this, clientId);
        }
    }

    public void kickOut() {
        connectionHandler.sendImediate("KILL|");
        isKickOut = true;
        stop();
    }

    public void processRequest(String request) {
        try {
            String hackerName = gameManager.getHackerName(clientName);
            if (hackerName != null) {
//                log(clientName + ":" + request);
            }
            if (isEnterTable) {
                gameTable.processMessage(request, playerId);
            } else {
                gameManager.processMessage(request, this);
            }
        } catch (Exception ex) {
//            Debug.info("request error :" + request);
//            Debug.traceException(request, ex);
            ex.printStackTrace();
            stop();
        }
    }

    public void setGameTable(GameTable table) {
        this.gameTable = table;
    }

    public void setEnterTable(boolean b) {
        isEnterTable = b;
    }

    public long getClientId() {
        return this.clientId;
    }

    public void removeClient(ClientManager client) {
        this.serverManager.removeClient(client, client.getClientId());
    }
//-----------------------------------------------------------------------------

    public void setSmsInfo(List<String> list) {
        listSmsInfo = list;
    }

    public void setPlayer(GamePlayer player) {
        this.player = player;
    }

    public void updateMateMoney(long deltaMoney) {
        String name = getMateName();
        long money = getMateMoney();
        money += deltaMoney;
        dataEngine.updateMoney(money, name);
    }

    public List<UserInfo> getTopLevel() {
        return this.dataEngine.getTopLevel();
    }

    public List<UserInfo> getTopRich() {
        return this.dataEngine.getTopRich();
    }

    public List<ChildInfo> getChildInfo() {
        return this.dataEngine.getChildInfo(clientName);
    }

    public List<ChildInfo> getChildInfo(String name) {
        return this.dataEngine.getChildInfo(name);
    }

    public List<FriendInfo> getListFriend() {
        return this.dataEngine.getListFriend(clientName);
    }

    public void setUserOnline(int state) {
        this.dataEngine.setUserOnline(state, clientName);

    }

//    public void setUserName(String name) {
//        this.clientName = name;
//    }
    public void updateLastLogin() {
        this.dataEngine.updateLastLogin(clientName);
    }

    public void setUserName(String name) {
        this.clientName = name;
        this.clientThread.setName(name);
        this.connectionHandler.setReaderName(name);
        inventory = dataEngine.getUserListItem(clientName);
    }

    public boolean isLoadMessage() {
        if (listMessage == null) {
            return false;
        }
        return true;
    }

    public List<UserMessage> getMessage() {
        if (listMessage == null) {
            listMessage = this.dataEngine.getMessage(clientName);
        }
        return this.listMessage;
    }

    public void changeLoginId() {
        this.dataEngine.changeLoginId(clientId, clientName);
    }

    public String getUserName() {
        return this.clientName;
    }

    public long getUserId() {
        return this.clientId;
    }

    public long getUserMoney() {
        return this.dataEngine.getUserMoney(clientName);
    }

    public int getUserLevel() {
        return this.userInfo.getLevel();
    }

    public synchronized boolean sendMessage(String message) {
        if (connectionHandler == null) {
            return false;
        }
        return connectionHandler.sendMessage(message);
    }

    public void setStatus(String s) {
        if (s.equals("0")) {
            userInfo.setStatus("");
            dataEngine.insertUserStatus(clientName, "");
        } else {
            userInfo.setStatus(s);
            dataEngine.insertUserStatus(clientName, s);
        }
    }

    @Override
    public void run() {

        while (isRunning) {
            try {
                Thread.sleep(THREAD_SLEEP);
            } catch (InterruptedException ex) {
            }
            if (!inQueue.isEmpty()) {
                processRequest(inQueue.elementAt(0));
                countPing = 0;
                startTime = System.currentTimeMillis();
                inQueue.removeElementAt(0);
            } else {
                int delay = (isEnterTable ? DELAY_PING : DELAY_OUT);
                long currrentTime = System.currentTimeMillis();
                if (currrentTime - startTime > delay) {
                    sendMessage("PING|");
                    startTime = System.currentTimeMillis();
                    countPing++;
                    if (countPing == 2) {
                        startTimeDb = -1;
                        stop();
                    }
                }
            }
            if (isEnterTable) {
                long currrentTime = System.currentTimeMillis();
                if (currrentTime - startTimeDb > timeExpireDb && startTimeDb != -1) {
                    stop();
                    startTimeDb = -1;
                }
            }
        }
    }

    @Override
    public void addQueue(String request) {
        inQueue.addElement(request);
    }

    public Socket getClientSocket() {
        return this.clientSocket;
    }

    public ClientManager getClient(long userId) {
        return this.serverManager.getClient(userId);
    }

//------------------------------ITEM------------------------------------------
    public List<ShopHistoryItem> getListShopHistory() {
        return dataEngine.getUserShopHistory(clientName);
    }

    public void removeRing() {
        for (int i = 0; i < inventory.size(); i++) {
            if (inventory.get(i).getId() == 3) {
                removeItem(i);
                return;
            }
        }
    }

    public boolean hasRing() {
        for (int i = 0; i < inventory.size(); i++) {
            if (inventory.get(i).getId() == 3) {
                applyItem(i);
                return true;
            }
        }
        return false;
    }

    public boolean hasActivedSpecialItem() {
        for (int i = 0; i < inventory.size(); i++) {
            if (inventory.get(i).getId() < 3 && inventory.get(i).isActived()) {
                return true;
            }
        }
        return false;
    }

    public int getActivedItemId() {
        int id = 2;
        for (int i = 0; i < inventory.size(); i++) {
            if (inventory.get(i).isActived() && inventory.get(i).getId() < id) {
                id = inventory.get(i).getId();
            }
        }
        return id;
    }

    public void shopping(String request) {
        shop.processMessage(request);
    }

    public void addItem(Item item) {
        inventory.add(item);
        dataEngine.insertNewBuyItem(0, item.getId(), clientName, item.getTime());
    }

    public void removeItem(int index) {
        if (index < inventory.size()) {
            this.dataEngine.deleteItemUsed(clientName, inventory.get(index).getStartingTime());
            inventory.remove(index);
        }
    }

    public void setItemInfo(List<ListItem> list) {
        listItemInfo = list;
        itemInfo = new ItemInfo();
        itemInfo.setNumberItem(listItemInfo.size());
        for (int i = 0, l = listItemInfo.size(); i < l; i++) {
            itemInfo.setItemLuckPercent(i, listItemInfo.get(i).getLuckyPercent());
            itemInfo.setItemName(i, listItemInfo.get(i).getName());
            itemInfo.setItemPrice(i, listItemInfo.get(i).getItemPrice());
            itemInfo.setItemTimeLimit(i, listItemInfo.get(i).getTimeLimit());
        }
    }

    public ItemInfo getItemInfo() {
        return itemInfo;
    }

    public int getItemUse() {
        int id = 4;
        for (int i = 0; i < inventory.size(); i++) {
            if (inventory.get(i).isActived() && inventory.get(i).getId() < id) {
                id = inventory.get(i).getId();
            }
        }
        return id;
    }

    public Item getItem(int index) {
        return inventory.get(index);
    }

    public void applyItem(int index) {
        if (!inventory.get(index).isActived()) {
            Timestamp oldStartTime = inventory.get(index).getTime();
            Timestamp newTime = DateUtil.newTimestamp();
            inventory.get(index).applyItem(newTime);
            dataEngine.activateItem(newTime, oldStartTime, clientName, inventory.get(index).getId());
        }
        if (inventory.get(index).getId() > AVATAR_CONST) {
            dataEngine.setAvatar(inventory.get(index).getId() - AVATAR_CONST, clientName);
            userInfo.setAvatarId(inventory.get(index).getId() - AVATAR_CONST);
        }
    }

    public void updateInventory() {
        for (int i = inventory.size() - 1; i >= 0; i--) {
            if (inventory.get(i).isTimeOut()) {
                removeItem(i);
            }
        }
        boolean hasAvatar = false;
        for (int i = 0; i < inventory.size(); i++) {
            if (inventory.get(i).isActived() && inventory.get(i).getId() > AVATAR_CONST) {
                hasAvatar = true;
                break;
            }
        }
        if (!hasAvatar) {
            dataEngine.setAvatar(0, clientName);
            userInfo.setAvatarId(0);
        } else {
            if (userInfo.getAvatarId() == 0) {
                for (int i = inventory.size() - 1; i >= 0; i--) {
                    if (inventory.get(i).isActived() && inventory.get(i).getId() > AVATAR_CONST) {
                        dataEngine.setAvatar(inventory.get(i).getId() - AVATAR_CONST, clientName);
                        userInfo.setAvatarId(inventory.get(i).getId() - AVATAR_CONST);
                    }
                }
            }
        }
    }

    public boolean hasSpeaker() {
        for (int i = 0; i < inventory.size(); i++) {
            if (inventory.get(i).getId() == 4) {
                applyItem(i);
                return true;
            }
        }
        return false;
    }

    public int getNumberItem() {
        return inventory.size();
    }

    public void deleteSpeaker() {
        for (int i = 0; i < inventory.size(); i++) {
            if (inventory.get(i).getId() == 4) {
                removeItem(i);
                break;
            }
        }
    }

//---------------------------USER INFO------------------------------------------
    public void setMateInfo(MateInfo mateInfo) {
        this.mateInfo = mateInfo;
    }

    public MateInfo getMateInfo(String name) {
        return this.dataEngine.getMateInfo(name);
    }

    public boolean checkFriend(String friendName) {
        return this.dataEngine.checkFriend(clientName, friendName);
    }

    public void insertNewFriend(String friendName) {
        dataEngine.insetNewFriend(clientName, friendName);
    }

    public void marryUser(String userName, String friend) {
        dataEngine.marryUser(userName, friend);
    }

    public void insertChild(String childName, int sexChild) {
        if (mateInfo == null) {
            mateInfo = dataEngine.getMateInfo(clientName);
        }
        this.dataEngine.insertChild(mateInfo.getFamilyId(), childName, sexChild);
    }

    public void deleteFriend(String userName, String friend) {
        this.dataEngine.deleteFriend(userName, friend);
    }

    public UserInfo getUserInfo(String name) {
        return this.dataEngine.getUserInfo(name);
    }

    public MateInfo getMateInfo() {
        mateInfo = dataEngine.getMateInfo(clientName);
        return mateInfo;
    }

    public String getMateName() {
        if (mateInfo == null) {
            mateInfo = dataEngine.getMateInfo(clientName);
        }
        return (clientName.equals(mateInfo.getMateName1()) ? mateInfo.getMateName2() : mateInfo.getMateName1());
    }

    public long getMateMoney() {
        String name = getMateName();
        return dataEngine.getUserMoney(name);
    }
//--------------------------------------------------------------------------------

    public void playLuckyCoint(String message) {
        xengGame.processMessage(message);
    }
//----------------------------------------------------------------------------

    public void updateLevel(int newLevel) {
        userInfo.setLevel(newLevel);
        dataEngine.updateLevel(clientName, newLevel);
    }

    public void updateWin(int newWin) {
        userInfo.setNumberWin(newWin);
        dataEngine.updateWin(clientName, newWin);
    }

    public void updateLose(int newLose) {
        userInfo.setNumbeLose(newLose);
        dataEngine.updateLose(clientName, newLose);
    }

    public void updateMoneyDelta(long deltaMoney) {
        if (userInfo == null) {
            userInfo = dataEngine.getUserInfo(clientName);
        }
        long currentMoney = this.userInfo.getMoney();
        currentMoney += deltaMoney;
//        userInfo.setMoney(currentMoney);
        updateMoneyToDataBase(currentMoney);
    }

    public void updateMoneyToDataBase(long numberMoney) {
        userInfo.setMoney(numberMoney);
        dataEngine.updateMoney(numberMoney, clientName);
    }

    public void setMoney(long numberMoney) {
        this.userInfo.setMoney(numberMoney);
        dataEngine.updateMoney(numberMoney, clientName);
        sendMessage("SETMONEY|" + numberMoney);
    }
//-------------------------------------------------------------------------------

    public void deleteMessage(int messageId) {
        dataEngine.deleteMessage(listMessage.get(messageId).getUserSend(), clientName, listMessage.get(messageId).getTime());
    }

    public void setReadMessage(int msgId) {
        UserMessage message = listMessage.get(msgId);
        message.setIsRead(1);
        dataEngine.setReadMessage(message.getUserSend(), clientName, message.getTime());
    }

    private String convertTelcoCode(String telcoCode) {
        if (telcoCode.equals("MOBI")) {
            return "VMS";
        } else if (telcoCode.equals("VINA")) {
            return "VNP";
        } else {
            return "VTT";
        }
    }

    public void useCard(String issuer, String cardCode, String cardSerial) {
        issuer = convertTelcoCode(issuer);
        ICardCharger cardCharger = serverManager.getCardCharger();
        int result = cardCharger.userCard(cardSerial, cardCode, issuer);
        dataEngine.logUseCard(issuer, cardSerial, cardCode, result, clientName);
        if (result >= 10000) {
            //so tien nap
            int moneyCharge = result;
//            dataEngine.logUseCardAmount(cardSerial, cardCode, transRef, String.valueOf(moneyCharge));
            //them vao tai khoan
            int ratio = 15;
//            serverManager.logUserStatus(clientName + " nap the thanh cong menh gia " + moneyCharge, LogDef.LOG_LEVEL.LOG_INFO);
            updateMoneyDelta(moneyCharge * ratio);
            gameManager.sendMessage(player.parent, "Thông báo", clientName, UserMessage.MESSAGE_NORMAL,
                    "Bạn vừa nạp " + (moneyCharge * ratio) + " xu vào tài khoản . Xin cảm ơn");
            sendMessage("USECARD|Nạp thẻ thành công. Xin cảm ơn");
        } else {
            sendMessage("USECARD|Nạp thẻ không thành công.");
        }

    }
    //------------------------------------------------------------------------------

    public void sendImediate(String string) {
        connectionHandler.sendImediate(string);
    }

    public void sendMessageToUser(String userReceive, Timestamp timeSend, int kind, String message) {
        this.dataEngine.insertNewMessenger(clientName, userReceive, message, timeSend, kind);
    }

    public void sendMessageToUser(String userSend, String userReceive, Timestamp timeSend, int kind, String messenger) {
        this.dataEngine.insertNewMessenger(userSend, userReceive, messenger, timeSend, kind);
    }

    public void resetTimeDb() {
        this.startTimeDb = -1;
    }

    public void setStartTimeDb(int numberPlays) {
        switch (numberPlays) {
            case 2:
                timeExpireDb = 80000;
                break;
            case 3:
                timeExpireDb = 120000;
                break;
            case 4:
                timeExpireDb = 200000;
                break;
        }
        this.startTimeDb = System.currentTimeMillis();
    }

//    public void log(String message) {
//        serverManager.logUserStatus(message, LogDef.LOG_LEVEL.LOG_INFO);
//    }
    public UserInfo getUserInfo() {
        this.userInfo = this.dataEngine.getUserInfo(clientName);
        return userInfo;
    }

    public int getAvatarId() {
        return userInfo.getAvatarId();
    }

    @Override
    public boolean isRunning() {
        return isRunning;
    }

    void start() {
        isRunning = true;
        clientThread = new Thread(this);
        clientThread.start();
    }

    public void setThreadName(String name) {
        clientThread.setName(name);
    }

    public void checkSms() {
        int numberLimit = dataEngine.countSmsLimit(clientName);
        if (numberLimit >= 1) {
            sendMessage("CHECKSMS|0");
            return;
        }
        int sumCost = dataEngine.sumSmsCost(clientName);
        if (sumCost > 135000) {
            sendMessage("CHECKSMS|2");
            return;
        }
        sendMessage("CHECKSMS|1");
    }

    public void setCompanyId(int companyId) {
        this.companyId = companyId;
    }

    public int getCompanyId() {
        return companyId;
    }

    public void chargeMoneySms(String serviceNumber, String userCharge) {
        userCharge = userCharge.trim().toLowerCase();
        Debug.info("user charge sms :" + userCharge);
        GamePlayer playerCharge = gameManager.getPlayer(userCharge);
        if (playerCharge != null) {
            // neu truong hop dang online
            UserInfo userChargeInfo = playerCharge.getUserInfo();
            if (userChargeInfo.getActivated() == 0 && serviceNumber.equals(userChargeInfo.getNumberActivate())) {
                dataEngine.activateAcc(userCharge, userChargeInfo.getCompanyId());
                gameManager.sendMessage(playerCharge.parent, "Thông báo", userCharge, UserMessage.MESSAGE_NORMAL,
                        "Bạn vừa kích hoạt tài khoản thành công . Xin cảm ơn");
            } else {
                Debug.info("before update :" + playerCharge.getUserName() + "," + playerCharge.getMoney());
                playerCharge.updateMoneyDelta(getGold(serviceNumber));
                Debug.info("after update :" + playerCharge.getUserName() + "," + playerCharge.getMoney());
                gameManager.sendMessage(playerCharge.parent, "Thông báo", userCharge, UserMessage.MESSAGE_NORMAL,
                        "Bạn vừa nạp " + getGold(serviceNumber) + " xu vào tài khoản . Xin cảm ơn");
            }
        } else {
            UserInfo userChargeInfo = dataEngine.getUserInfo(userCharge);
            if (userChargeInfo != null) {
                if (userChargeInfo.getActivated() == 0 && serviceNumber.equals(userChargeInfo.getNumberActivate())) {
                    activateAccount(userCharge);
                } else {
                    Debug.info("after update :" + userChargeInfo.getUserName() + "," + userChargeInfo.getMoney());
                    dataEngine.updateMoney(userChargeInfo.getMoney() + getGold(serviceNumber), userCharge);
                    dataEngine.insertNewMessenger("Thông báo", userCharge, "Bạn vừa nạp " + getGold(serviceNumber) + "xu vào tài khoản . Xin cảm ơn",
                            DateUtil.newTimestamp(), UserMessage.MESSAGE_NORMAL);
                    userChargeInfo = dataEngine.getUserInfo(userCharge);
                    Debug.info("after update :" + userChargeInfo.getUserName() + "," + userChargeInfo.getMoney());
                }
            }
        }
    }

    private int getGold(String serviceNumber) {
        return getCostNumber(serviceNumber) * 10;
    }

    public int getCostNumber(String number) {
        int cost = 500;
        if (number.charAt(1) == '0') {
            cost = 500;
        } else if (number.charAt(1) == '1') {
            cost = 1000;
        } else if (number.charAt(1) == '2') {
            cost = 2000;
        } else if (number.charAt(1) == '3') {
            cost = 3000;
        } else if (number.charAt(1) == '4') {
            cost = 4000;
        } else if (number.charAt(1) == '5') {
            cost = 5000;
        } else if (number.charAt(1) == '6') {
            cost = 10000;
        } else if (number.charAt(1) == '7') {
            cost = 15000;
        }
        return cost;
    }

    private void activateAccount(String userCharge) {
//        Debug.d("user charge length :" + userCharge.trim().length());
        ClientManager client = gameManager.getWaitActiveClient(userCharge);
        if (client != null) {
            dataEngine.activateAcc(userCharge, client.getCompanyId());
            client.sendMessage("GRANTED|");
            dataEngine.insertNewMessenger("Thông báo", userCharge, "Bạn vừa kích hoạt tài khoản thành công . Xin cảm ơn",
                    DateUtil.newTimestamp(), UserMessage.MESSAGE_NORMAL);
        }
    }

    public void setHackerName(String hackerName) {
    }

    public void sendSmsInfo(int companyId) {
        CompanyInfo companyInfo = dataEngine.getSmsInfo(companyId);
        if (companyInfo != null) {
            StringBuilder msgBuilder = new StringBuilder();
            msgBuilder.append("SMSINFO");

            msgBuilder.append("|").append(companyInfo.getCost1()).append("|").append(companyInfo.getGameMoney1()).
                    append("|").append(companyInfo.getNumberCharge1()).append("|").append(companyInfo.getSynTax());

            msgBuilder.append("|").append(companyInfo.getCost2()).append("|").append(companyInfo.getGameMoney2()).
                    append("|").append(companyInfo.getNumberCharge2()).append("|").append(companyInfo.getSynTax());

            msgBuilder.append("|").append(companyInfo.getCost3()).append("|").append(companyInfo.getGameMoney3()).
                    append("|").append(companyInfo.getNumberCharge3()).append("|").append(companyInfo.getSynTax());

            sendMessage(msgBuilder.toString());
        }
    }

    void enterServer(int numberLogin) {
        dataEngine.enterServer(clientName, clientId, device, numberLogin);
    }

    public void sendResetInfo(String name) {
        UserInfo resetInfo = getUserInfo(name);
        if (resetInfo == null) {
            sendMessage("RSMK|0|Tài khoản này chưa đăng ký");
        } else {
            CompanyInfo companyInfo = dataEngine.getSmsInfo(resetInfo.getCompanyId());
            sendMessage("RSMK|1|" + companyInfo.getNumberActive() + "|" + companyInfo.getSynTax());
        }
    }

    @Override
    public String getName() {
        return clientThread.getName();
    }

    public void checkActivate() {
        connectionHandler.sendMessage("CHECK_ACTIVATE|" + dataEngine.checkActivate(clientName));
    }
}
